/**
Modbus RTU 组成如下
| 起始位 | 设备地址 | 功能码 | 数据量 | 数据 | crc低 | crc高 | 结束符 |
|--------------------------------------------------------------|
| 1byte | 1byte   |1byte | 1byte | nbyte| 1byte| 1byte | 无    |
 */

#ifndef _MODBUS_H
#define _MODBUS_H

#include <stdint.h>
#include "HardwareSerial.h"

#define RTU_MAX_DATA_SIZE           128     /** 数据最大长度 */
#define RTU_DEF_START_BYTE          0x5A    /** 默认起始字节 */
#define RTU_DEF_END_BYTE            0xB5    /** 默认结束字节 */

#define RTU_HEAD_LEN                4       /** 协议头部长度 */
#define RTU_TAIL_LEN                2       /** 协议尾部长度 */
#define RTU_FORMAT_LEN              (RTU_HEAD_LEN + RTU_TAIL_LEN)

class Modbus {
public:
    typedef uint16_t (*Crc16Callback_t)(uint8_t *data, uint32_t len);

    typedef struct {
        uint8_t  startByte;
        uint8_t  devAddr;
        uint8_t  funCode;
        uint8_t  dataLen;
        uint8_t  *data;
        uint16_t crc;

    } RTUFrame_t;

    typedef enum : uint8_t {
        RTU_OK,
        SEND_FAIL,
        READ_TIMEOUT,
        START_ERROR,
        DEV_ERROR,
        CODE_ERROR,
        LENGTH_ERROR,
        CRC_ERROR,
        _LAST_
    } Res_t;

public:
    Modbus(HardwareSerial *serial) : Serial(serial) {}

    ~Modbus();

    int begin(uint8_t start, uint8_t dev_addr, uint32_t timeout = 1000);
    void setCRC(Crc16Callback_t callback);

    int sendFrame(uint8_t fun_code, uint8_t *data, uint32_t len);
    int sendFrame(uint8_t fun_code, uint8_t data);
    int sendFrame(RTUFrame_t *frame);

    int readFrame(RTUFrame_t *frame);
    int readFrame(uint8_t fun_code, uint8_t *data, uint32_t len);
    int timeReadFrame(RTUFrame_t *frame);

    Res_t requestSend(uint8_t fun_code, uint8_t *data, uint32_t len);

protected:
    uint32_t _timeout;
    uint8_t  _startByte;
    uint8_t  _devAddr;

    uint8_t txBuffer[RTU_FORMAT_LEN + RTU_MAX_DATA_SIZE];
    uint8_t rxBuffer[RTU_FORMAT_LEN + RTU_MAX_DATA_SIZE];


    Crc16Callback_t crc16;
    HardwareSerial  *Serial;

private:

};


#endif //_MODBUS_H
